<template>
  <div>
    <!-- 对于dialog 组件，可以支持如下四种关闭的方式
      1.  点击遮罩层上, 会导致弹窗关闭
      2.  按下esc键。会导致弹窗关闭
      3.  点击右上角的X按钮。会导致弹窗关闭
      4.  点击确认和取消, 可以自己写弹窗关闭(留下)
      5、这四种方式，dialog内部是怎么关闭的呢？
      不是直接隐藏了标签，而是改变visible对应的变量为false
      内部检测visible属性值为false，才隐藏dialog标签的
      6、组件通信：子->父范围的dialogVisible变量
      以前技术：
         (1):子组件内恰当时机，this.$emit('自定义事件名字'，值)  用this.$emit触发自定义事件
         (2):父组件内，在子组件标签上绑定@自定义事件名="事件处理函数"
         在事件处理函数中，接到子传出的值，赋予给父的变量
      .sync语法糖：本质上还是用的上面的技术，但是语法上有些简化
         (1)：子组件内恰当时机，this.$emit('update:props变量名'，值)
         (2)：父组件内，给子组件对应的props变量名.sync="父范围变量名"
      .sync作用：它会在运行时，给当前绑定自定义事件名和事件处理函数
              @update:visible="val=>dialogVisible=val"
                :visible.sync="dialogVisible"还在
      .sync场景：子->父快速传值并赋予给父范围内的变量
                如果子->父要执行逻辑代码很多，这个.sync就不能用了，还用以前的技术

      知识点：props变量是只读的，不能直接重新赋值(会报Vue警告)(尽量遵守单向数据流)
      原因：Vue设计上，父如果重新渲染，会给props里的变量重新赋值，原来父给子组件内props赋予的值将会被覆盖丢失。所以不建议直接修改props里面的变量
      解决：
            方式(1) 用data或computed代替(后面讲)
            方式(2) 快速改变父范围的变量(双向绑定)->让父把值改完再流回给props影响子组件(单向数据流)
      单向数据流：尽量让父改变值，重新给props赋值(父->子)

      -->
    <!-- :visible.sync="dialogVisible" -->
    <el-dialog
      :title="isEdit?'编辑子部门':'添加子部门'"
      :visible="dialogVisible"
      width="50%"
      :before-close="handleClose"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :show-close="false"
      @update:visible="val=>$emit('update:dialogVisible',false)"
      @close="dialogCloseFn"
    >
      <!-- 信息内容部分 -->
      <el-form
        ref="deptForm"
        :model="form"
        :rules="rules"
        label-width="120px"
      >
        <el-form-item
          label="部门名称"
          prop="name"
        >
          <el-input
            v-model="form.name"
            style="width:80%"
            placeholder="1-50个字符"
          />
        </el-form-item>
        <el-form-item
          label="部门编码"
          prop="code"
        >
          <el-input
            v-model="form.code"
            style="width:80%"
            placeholder="1-50个字符"
          />
        </el-form-item>
        <el-form-item
          label="部门负责人"
          prop="manager"
        >
          <el-select
            v-model="form.manager"
            style="width:80%"
            placeholder="请选择"
          >
            <el-option
              v-for="item in employeeSimpleList"
              :key="item.id"
              :value="item.username"
            />
          </el-select>
        </el-form-item>
        <el-form-item
          label="部门介绍"
          prop="introduce"
        >
          <el-input
            v-model="form.introduce"
            style="width:80%"
            placeholder="1-300个字符"
            type="textarea"
            :rows="3"
          />
        </el-form-item>
      </el-form>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <!-- 所以不要直接改变props里的值dialogVisible，要绑定自定义点击事件 -->
        <!-- <el-button @click="dialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="dialogVisible = false">确 定</el-button> -->
        <el-button @click="cancleFn">取 消</el-button>
        <el-button
          type="primary"
          @click="confirmFn"
        >确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    // 页面上控制diaglog是否显示
    dialogVisible: {
      type: Boolean
    },
    employeeSimpleList: {
      type: Array,
      default: () => [] //eslint 要求引用类型必须有默认值
    },
    originList: {
      type: Array,
      default: () => [] // 部门列表数组(扁平结构，存放4对key/value)
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    // 当前编辑的部门id
    clickDepartId: {
      type: String,
      default: ''
    }
  },
  data() {
    // 校验部门编码是否重复
    const validCode = (rule, value, callback) => {
      // 新增部门时，code不能和所有人重复
      // 判断是否能否找到对应的部门，如果找到了则返回该对象
      let codeList = this.originList.map(item => item.code)

      // 编辑部门：
      // 问题：自己编码和自己冲突了，正确效果是，编辑时，自己的部门编码可以直接用
      // 原因：value和所有部门对比
      // 解决：把自己从所有人里淘汰出去，留下剩下的(filter)
      if (this.isEdit) {
        // 把自己的id过滤掉，判断是否能否找到对应的部门，如果找到了则返回该对象
        // const codeList = this.originList.filter(item => item.id !== this.clickDepartId).map(item => item.code)
        const newArr = this.originList.filter(item => item.id !== this.clickDepartId)
        codeList = newArr.map(item => item.code)
      }
      // 如果存在该对象，则说明编码已经存在，抛出错误
      codeList.includes(value) ? callback(new Error('部门编码' + value + '已经存在')) : callback()
    }
    // 同级部门禁止出现重复名字部门
    const validName = (rule, value, callback) => {
      // 新增部门名字：先找到同级部门对象
      // 数据规律：子部门pid=父部门id
      // 筛选出一级部门不能有重复的
      let nameList = this.originList.filter(item => item.pid === this.clickDepartId).map(item => item.name)

      // // 如果是编辑的情况
      if (this.isEdit) {
        // 找到部门的当前对象
        const dept = this.originList.find(item => item.id === this.clickDepartId)
        // 取出父级的 id (当前对象的pid)
        const pid = dept.pid
        // 过滤，筛选出同一级别的数据, 但是id不包含当前编辑部门的id, 映射返回name名字数组
        nameList = this.originList.filter(item => item.pid === pid && item.id !== this.clickDepartId).map(item => item.name)
      }

      // 判断最新输入的部门名称是否存在
      nameList.includes(value) ? callback(new Error('部门名字' + value + '已经被占用了')) : callback()
    }
    return {
      form: {
        name: '', // 部门名称
        code: '', // 部门编码
        manager: '', // 部门管理者
        introduce: '' // 部门介绍
      },
      // rules的key名要和form的key名一致
      // trigger是form表单触发校验的动作，取值'blur' 'change'
      rules: {
        name: [
          { required: true, message: '部门名称不能为空', trigger: 'blur' },
          { min: 2, max: 20, message: '部门名称要求2-20个字符', trigger: 'blur' },
          { validator: validName, trigger: 'blur' }
        ],
        code: [
          { required: true, message: '部门编码不能为空', trigger: 'blur' },
          { min: 1, max: 20, message: '部门编码要求1-20个字符', trigger: 'blur' },
          { validator: validCode, trigger: 'blur' }
        ],
        manager: [{ required: true, message: '部门负责人不能为空', trigger: 'blur' }],
        introduce: [
          { required: true, message: '部门介绍不能为空', trigger: 'blur' },
          { min: 1, max: 300, message: '部门介绍要求1-300个字符', trigger: 'blur' }
        ]
      }
    }
  },
  // data() {
  //   return {
  //     dialogVisible: false // 添加子部门->控制dialog显示/隐藏
  //   }
  // },
  // 需求：把props接到的值，转移赋予给data
  // 解决：用watch侦听props值的变化，再转移给data里面的变量
  // watch: {
  //   dialogVisible() {
  //     this.showDialog = this.dialogVisible
  //   }
  // },
  methods: {
    // 添加子部门的dialog在关闭前的回调函数
    handleClose(done) {
      this.$confirm('确认关闭？')
        .then(_ => {
          done()
        })
        .catch(_ => {})
    },
    // 点击取消
    cancleFn() {
      // this.$emit('dialogShowEV', false)  子传父方式1
      // 子传父方式2
      this.$emit('update:dialogVisible', false)
    },
    // 点击确定
    confirmFn() {
      // js兜底校验
      this.$refs.deptForm.validate(valid => {
        if (valid) {
          // 拿到表单数据用this.form因为按钮在表单外面
          // console.log(this.form)
          // 拷贝一个新的对象给父级axios使用，因为子组件要清空form表单，可能会影响到axiox的发送使用
          this.$emit('addDepartmentEV', { ...this.form })
          this.$emit('update:dialogVisible', false)
        }
      })
    },
    // 弹窗关闭后触发的回调函数
    dialogCloseFn() {
      // 这里不能写this.form='' 因为form是个对象
      // this.form = {}
      // 上面那种方法清空不了校验提示
      // 清除校验提示/清空表单
      this.$refs.deptForm.resetFields()
    }
  }
}
</script>

<style>
</style>
